package com.wolf.antlr;

import com.wolf.antlr.javascript.JavaScriptLexer;
import com.wolf.antlr.javascript.JavaScriptParser;
import com.wolf.antlr.javascript.JavaScriptParserBaseListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class JavascriptSearcher {
    static List<MethodFragment> searchFunctions(String fileName, JavascriptListenerImp listener) {
        Lexer lexer;
        try {
            lexer = new JavaScriptLexer(CharStreams.fromFileName(fileName));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        TokenStream tokenStream = new CommonTokenStream(lexer);
        JavaScriptParser parser = new JavaScriptParser(tokenStream);
        ParseTree tree = parser.program();
        ParseTreeWalker walker = new ParseTreeWalker();
        walker.walk(listener, tree);
        return listener.getMethodFragments();
    }

    public static void main(String[] args) {
        JavascriptListenerImp listener = new JavascriptListenerImp();
        String fileName = Main.parserArgs(args, listener);
        List<MethodFragment> methodFragments = searchFunctions(fileName, listener);
        methodFragments.forEach(methodFragment -> System.out.printf("%s, %s, %s, %s, %s\n",
                methodFragment.startIndex(),
                methodFragment.endIndex(),
                methodFragment.startLine(),
                methodFragment.endLine(),
                methodFragment.methodDeclaration()));
    }

    static class JavascriptListenerImp extends JavaScriptParserBaseListener implements IListener {
        private String getMethodDeclaration(JavaScriptParser.FunctionDeclarationContext ctx) {
            String functionName = ctx.identifier().getText();

// 获取参数列表
            List<String> parameters = new ArrayList<>();
            if (ctx.formalParameterList() != null) {
                for (JavaScriptParser.FormalParameterArgContext parameter : ctx.formalParameterList().formalParameterArg()) {
                    parameters.add(parameter.getText());
                }
            }

            return "function " +
                    functionName +
                    "(" +
                    String.join(", ", parameters) +
                    ")";
        }

        private String getMethodDeclaration(JavaScriptParser.ArrowFunctionContext ctx) {
            StringBuilder func_decl = new StringBuilder();
            // 获取参数列表
            String parameters = ctx.arrowFunctionParameters().getText();

            // 获取主体部分
            String body = ctx.arrowFunctionBody().getText();

            func_decl.append(parameters);
            func_decl.append(" => ");
            func_decl.append(body);
            return func_decl.toString();
        }

        @Override
        public void enterFunctionDeclaration(JavaScriptParser.FunctionDeclarationContext ctx) {
            super.enterFunctionDeclaration(ctx);
            String methodDeclaration = this.getMethodDeclaration(ctx);
            this.search(ctx, methodDeclaration);
        }

        @Override
        public void enterArrowFunction(JavaScriptParser.ArrowFunctionContext ctx) {
            super.enterArrowFunction(ctx);
            String methodDeclaration = this.getMethodDeclaration(ctx);
            this.search(ctx, methodDeclaration);
        }
    }
}
